#pragma once
// #include<iostream>
// #include<string>
// #include<unistd.h>
// #include<strings.h>

// #include <sys/types.h>         
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>

// #include<cerrno>
// #include<cstring>

// #include"Comm.hpp"
// #include"nocopy.hpp"
// #include"Log.hpp"
// #include"InetAddr.hpp"

// using namespace std;

// static const uint16_t defaultport = 8888; 
// static const uint16_t defaultfd = -1; 
// static const int defaultsize = 1024; 

// class UdpServer : public nocopy
// {
// public:
//     UdpServer(const string& ip,uint16_t port = defaultport)
//     :_ip(ip),_port(port),_sockfd(defaultfd)
//     {}
//     void Init()
//     {
//         //1. 创建套接字,创建成功后会返回 a ffile descriptor ，出错返回-1
//         _sockfd = socket(AF_INET,SOCK_DGRAM,0);
//         if(_sockfd < 0)//创建套接字失败
//         {
//             lg.LogMessage(Fatal,"socket errno, %d : %s\n",errno,strerror(errno));
//             exit(Socket_Err);
//         }
//         lg.LogMessage(Info,"socket success,sockfd : %d\n",_sockfd);
    
//         //2. 绑定，指定网络信息 相当于给套接字命名
//         struct sockaddr_in local;//该结构体 需要新加头文件：#include <netinet/in.h>、#include <arpa/inet.h>
        
//         //补充结构体sockaddr_in：
//         bzero(&local,sizeof(local));//将指定的空间的大小内存清零
//         local.sin_family = AF_INET;//协议家族 ，绑定网络通信的信息
//         //sin：s：socket in：inet（IP地址！）
//         local.sin_port = htons(_port);//将string的_port转换成网络序列，通过htons h:host、to、n:net、s:socket
//         local.sin_addr.s_addr = INADDR_ANY;//一般不固定一个ip，而是任意生成一个ip的动态绑定：INADDR_ANY == 0
       
//         // local.sin_addr.s_addr = inet_addr(_ip.c_str());//需要把uint16_t的ip转化成4字节的uint32_t的网络序列的ip，可以通过inet_addr
        
// //将刚刚设置好的网络信息和的文件信息进行绑定
//         int n = ::bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
//         if(n != 0)
//         {
//             lg.LogMessage(Fatal,"bind errno, %d : %s\n",errno,strerror(errno));
//             exit(Bind_Err);
//         }
// //绑定完成后就：服务器就已经初始化完成了
    
//     }
//     void Start() 
//     {
//         char buffer[defaultsize];
//         //服务器永远不退出！
//         for(;;)
//         { 
//             //服务器进行udp收发消息
//             struct sockaddr_in peer;
//             socklen_t len = sizeof(peer);//socklen_t 就是无符号整形

//             ssize_t n = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
//             if(n > 0)
//             { 
//                 InetAddr addr(peer);//新写一个类，对类进行封装

//                 buffer[n] = 0;//当字符串

//                 cout << "[" << addr.PrintDebug() << "]# "<<  buffer << endl;
           
//             //给对方发消息：
//                 sendto(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,len);
            
//             }
        
//         }
//     }
//     ~UdpServer()
//     {}
// private:
//     string _ip;
//     uint16_t _port;
//     int _sockfd;
// };


// 优化代码不绑定特定的ip
#include<iostream>
#include<string>
#include<unistd.h>
#include<strings.h>

#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include<cerrno>
#include<cstring>
#include<functional> 

#include"Comm.hpp"
#include"nocopy.hpp"
#include"Log.hpp"
#include"InetAddr.hpp"
using namespace std;

using func_t = function<string(string)>;

static const uint16_t defaultport = 8888; 
static const uint16_t defaultfd = -1; 
static const int defaultsize = 1024; 
//聚焦在IO上
class UdpServer : public nocopy
{
public:
    UdpServer(func_t OnMessage,uint16_t port = defaultport)
    :_port(port),_sockfd(defaultfd),_OnMessage(OnMessage)
    {}
    void Init()
    {
        //1. 创建套接字,创建成功后会返回 a ffile descriptor ，出错返回-1
        _sockfd = socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd < 0)//创建套接字失败
        {
            lg.LogMessage(Fatal,"socket errno, %d : %s\n",errno,strerror(errno));
            exit(Socket_Err);
        }
        lg.LogMessage(Info,"socket success,sockfd : %d\n",_sockfd);
    
        //2. 绑定，指定网络信息 相当于给套接字命名
        struct sockaddr_in local;//该结构体 需要新加头文件：#include <netinet/in.h>、#include <arpa/inet.h>
        
        //补充结构体sockaddr_in：
        bzero(&local,sizeof(local));//将指定的空间的大小内存清零
        local.sin_family = AF_INET;//协议家族 ，绑定网络通信的信息
        //sin：s：socket in：inet（IP地址！）
        local.sin_port = htons(_port);//将string的_port转换成网络序列，通过htons h:host、to、n:net、s:socket
        local.sin_addr.s_addr = INADDR_ANY;//一般不固定一个ip，而是任意生成一个ip的动态绑定：INADDR_ANY == 0
       
        // local.sin_addr.s_addr = inet_addr(_ip.c_str());//需要把uint16_t的ip转化成4字节的uint32_t的网络序列的ip，可以通过inet_addr
        
//将刚刚设置好的网络信息和的文件信息进行绑定
        int n = ::bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n != 0)
        {
            lg.LogMessage(Fatal,"bind errno, %d : %s\n",errno,strerror(errno));
            exit(Bind_Err);
        }
//绑定完成后就：服务器就已经初始化完成了
    
    }
    void Start() 
    {
        char buffer[defaultsize];
        //服务器永远不退出！
        for(;;)
        { 
            //服务器进行udp收发消息
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);//socklen_t 就是无符号整形

            ssize_t n = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
            if(n > 0)
            { 
                InetAddr addr(peer);//新写一个类，对类进行封装

                buffer[n] = 0;//当字符串

                //收到消息，Onmessage处理接收到的消息
                string response = _OnMessage(buffer);//交给函数，对字符串信息进行处理
                // cout << "[" << addr.PrintDebug() << "]# "<<  buffer << endl;
                cout << response << endl;
                //给对方发消息：
                sendto(_sockfd,response.c_str(),response.size(),0,(struct sockaddr*)&peer,len);
            
            }
        
        }
    }
    ~UdpServer()
    {}
private:
    // string _ip;
    uint16_t _port;
    int _sockfd;

    func_t _OnMessage;//回调
};